/**
 * @brief FreeRTOS应用示例
 * @details
 * @author 王炸物联网https://blog.csdn.net/wangyx1234?spm=1000.2115.3001.5343
 * @date 2022
 * @version 1.0
 * @copyright 版权所有，禁止用于商业用途
 */
#include <stdio.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_log.h"

#include "freertos/queue.h"
#include "freertos/event_groups.h"

#include "rom/ets_sys.h"

TaskHandle_t task1; // 任务1结构对象
TaskHandle_t task2;
TaskHandle_t task3;

static int task1_flag; 
static int task2_flag; 
          
static portMUX_TYPE s_my_task_mux;  //Mutex required due to SMP

static int s_share_counter = 0;                  // 全局共享计数器

/**
 * 初始化共享计数器
 * @param count 初始的计数器
 */
void share_counter_init (int count)
{
    s_share_counter = count;
}

void share_counter_process(bool flag)
{
    taskENTER_CRITICAL(&s_my_task_mux); // 你可以注释掉代码，来查看没有添加临界区时的情况。
    if(flag) {
        int var1 = s_share_counter;
        var1 = var1 + 1;
        // 注意，这里只是模拟任务执行过程被打断得情况，所以加了延时。实际情况下，临界区内，不能有延时。
        ets_delay_us(100*1000);
        s_share_counter = var1;
    } else {
        int var2 = s_share_counter;
        var2 = var2 - 1;
         // 注意，这里只是模拟任务执行过程被打断得情况，所以加了延时。实际情况下，临界区内，不能有延时。
        ets_delay_us(100*1000);
        s_share_counter = var2;
    }
    taskEXIT_CRITICAL(&s_my_task_mux); // 你可以注释掉代码，来查看没有添加临界区时的情况。
}

/**
 * 获取共享计数器值
 * @return 当前计数值
 */
int get_share_counter(void) 
{
    return s_share_counter;
}

/**
 * 任务的运行代码
 * @param param 任务初始运行参数
 */
static void task1_process(void *arg)
{
    while (1) {
        share_counter_process(true); 
        task1_flag++;
        if(task1_flag > 10) { // 加十次
            break;
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
    printf("task1 done\r\n");
    vTaskDelete(NULL);
}

static void task2_process(void *arg)
{
    while (1) {
        share_counter_process(false);
        task2_flag++;
        if(task2_flag > 10) { // 减十次
            break;
        }
        vTaskDelay(pdMS_TO_TICKS(100));
    }
    printf("task2 done\r\n");
    vTaskDelete(NULL);
}

static void task3_process(void *arg)
{
    // 添加一个足够大的延时，来获取两个任务执行运算的最终结果。实际上用事件组同步下更好。
    vTaskDelay(pdMS_TO_TICKS(3000));
    printf("task3 done, and counter=%d\r\n", get_share_counter());
    vTaskDelete(NULL);
}

static void init(void) {
    printf("Hello world!\n");

    /* Print chip information */
    esp_chip_info_t chip_info;
    esp_chip_info(&chip_info);
    printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
            CONFIG_IDF_TARGET,
            chip_info.cores,
            (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
            (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");

    printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
    vPortCPUInitializeMutex(&s_my_task_mux);
}

void app_main(void)
{
    init();
    /*
    static BaseType_t xTaskCreate(TaskFunction_t pvTaskCode, const char *constpcName, const int usStackDepth, 
    void *constpvParameters, UBaseType_t uxPriority, TaskHandle_t *constpxCreatedTask)*/
    xTaskCreate(&task1_process, "task1", 1024*2, (void *)"1", configMAX_PRIORITIES-1, &task1); // configMAX_PRIORITIES = 25
    xTaskCreate(&task2_process, "task2", 1024*2, (void *)"2", configMAX_PRIORITIES-2, &task2);
    xTaskCreate(&task3_process, "task3", 1024*2, (void *)"3", configMAX_PRIORITIES-3, &task3);
}
